package com.accedo.achievements.services.ajax.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.accedo.achievements.dataaccess.dao.impl.BadgeDaoImpl;
import com.accedo.achievements.dataaccess.dao.impl.UserDaoImpl;
import com.accedo.achievements.dataaccess.model.Badge;
import com.accedo.achievements.dataaccess.model.User;
import com.accedo.achievements.services.ajax.BadgeService;

/**
 * The business logic service of badge relevant functionality.
 * @author Bo Liang
 */
@Component
public class BadgeServiceImpl implements BadgeService {

	private static final Logger log = LoggerFactory.getLogger(BadgeServiceImpl.class);

	private User user; //injection
	private Badge badge; //injection
	
	private UserDaoImpl userDao; //injection
	private BadgeDaoImpl badgeDao; //injection
	
	// Constructor
	BadgeServiceImpl() {}; 
	
//	/**
//	 * Add badge to user object.
//	 * @param username 	user name
//	 * @param badge_sn	badge serial number
//	 */
//	public void addBadgeToUser(String username, String badge_sn) {
//		userDao.addBadgeToUser(username, badge_sn); 
//	}
	
	/**
	 * Get all badges in three state categories : finished, playing and none.
	 * <p>the sequence is grouped by the newest badge to the front.
	 * <p>finished state means this user already unlocked all achievements and obtained the badge.<br>
	 * playing state means this user has partly unlocked the achievements.<br>
	 * none state means this user has never unlocked any achievements related to the badge.
	 * @param username	user name
	 * @return			JSON badges<br>
	 * eg. {badges:[{badge_sn:'Badge009', badge_name:'HONG KONG', state:'playing'},
	 * {badge_sn:'Badge008', badge_name:'SHANGHAI', state:'none'}]}
	 */
	public JSONObject getJsonBadgesByUsername(String username) {
		log.debug("### Entering getJsonBadgesByUsername(username = {})", username);
		JSONObject jsonObject = new JSONObject();
		JSONArray jsonArray = new JSONArray();
		List<Badge> badgeList = new ArrayList<Badge>();
		Map<Integer, String> unlockedBadgeIdMap = new HashMap<Integer, String>();
		String state = "none";
		user = userDao.getUserByUsername(username); 
		
		// get all badges to the badge List
		badgeList = badgeDao.getBadgeList(); 
		// get user unlocked badges id to the unlocked badge id list
		unlockedBadgeIdMap = badgeDao.getActiveBadgeIdMapByUserId(user.getId());
		
		for (Iterator<Badge> iter = badgeList.iterator(); iter.hasNext(); ) {
			badge = iter.next();
			
			if (unlockedBadgeIdMap.containsKey(badge.getId())) {
				state = unlockedBadgeIdMap.get(badge.getId());	
			} else {
				state = "none";	
			}
			jsonObject.element("badge_sn", badge.getBadge_sn()); 
			jsonObject.element("badge_name", badge.getBadge_name()); 
			jsonObject.element("state", state); 
			jsonArray.add(jsonObject); 
			jsonObject.clear(); 
		}
		jsonObject.element("badges", jsonArray); 
		
		try {
			Thread.sleep(1800);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		log.debug("### Leaving getJsonBadgesByUsername() : {}", jsonObject);
		return jsonObject; 
	}
	
	/**
	 * Get all badges in three state categories : finished, playing and none.
	 * <p>the sequence is grouped by finished badge, playing badge and then none badge.
	 * <p>finished state means this user already unlocked all achievements and obtained the badge.<br>
	 * playing state means this user has partly unlocked the achievements.<br>
	 * none state means this user has never unlocked any achievements related to the badge.
	 * @param username	user name
	 * @return			JSON badges<br>
	 * eg. {badges:[{badge_sn:'Badge001', badge_name:'NEW YORK', state:'finished'},
	 * {badge_sn:'Badge009', badge_name:'HONG KONG', state:'playing'},
	 * {badge_sn:'Badge007', badge_name:'TORONTO', state:'none'}]}
	 */
	public JSONObject getJsonBadgesByUsernameForFriendShow(String username) {
		log.debug("### Entering getJsonBadgesByUsernameForFriendShow(username = {})", username);
		List<Badge> badgeList = new ArrayList<Badge>();
		Map<Integer, String> unlockedBadgeIdMap = new HashMap<Integer, String>();
		String state = "none";
		JSONObject jsonObject = new JSONObject();
		JSONArray jsonArray = new JSONArray();
		JSONArray jsonArrayFinished = new JSONArray();
		JSONArray jsonArrayPlaying = new JSONArray();
		JSONArray jsonArrayNone = new JSONArray();
		user = userDao.getUserByUsername(username); 
		
		// get all badges to the badge List
		badgeList = badgeDao.getBadgeList(); 
		// get user unlocked badges id to the unlocked badge id list
		unlockedBadgeIdMap = badgeDao.getActiveBadgeIdMapByUserId(user.getId());
		
		for (Iterator<Badge> iter = badgeList.iterator(); iter.hasNext(); ) {
			badge = iter.next();
			jsonObject.element("badge_sn", badge.getBadge_sn()); 
			jsonObject.element("badge_name", badge.getBadge_name());
			
			if (unlockedBadgeIdMap.containsKey(badge.getId())) {
				state = unlockedBadgeIdMap.get(badge.getId());	
				if (state == "playing") {
					jsonObject.element("state", state); 
					jsonArrayPlaying.add(jsonObject);
					
				} else if (state == "finished") {
					jsonObject.element("state", state);  
					jsonArrayFinished.add(jsonObject);	
				}
			} else {
				state = "none";	
				jsonObject.element("state", state);  
				jsonArrayNone.add(jsonObject);
			}
			jsonObject.clear();
			
		}
		jsonArray.addAll(jsonArrayFinished);
		jsonArray.addAll(jsonArrayPlaying);
		jsonArray.addAll(jsonArrayNone); 
		jsonObject.element("badges", jsonArray);
		
		try {
			Thread.sleep(1800);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		log.debug("### Leaving getJsonBadgesByUsernameForFriendShow() : {}", jsonObject);
		return jsonObject; 
	}

	public BadgeDaoImpl getBadgeDao() {
		return badgeDao;
	}

	@Resource
	public void setBadgeDao(BadgeDaoImpl badgeDao) {
		this.badgeDao = badgeDao;
	}

	public User getUser() {
		return user;
	}

	@Resource
	public void setUser(User user) {
		this.user = user;
	}

	public Badge getBadge() {
		return badge;
	}

	@Resource
	public void setBadge(Badge badge) {
		this.badge = badge;
	}

	public UserDaoImpl getUserDao() {
		return userDao;
	}

	@Resource
	public void setUserDao(UserDaoImpl userDao) {
		this.userDao = userDao;
	}
}
